/* system includes */
#include <string.h>
#include <stdlib.h>

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "FreeRTOSConfig.h"

/* project includes */
#include "user_interface.h"
#include "uart.h"
#include "commands.h"

static uint8_t ui_message[CFG_MAX_UI_MSG_SIZE];
static uint8_t *p_ui_message;
extern xQueueHandle xUart_Queue;

/**
 * User interface initialization
 *
 * @param  none
 * @return none
 *
 * @brief  create task for user interface
 *
 */
void user_interface_init(void)
{

    /* Create the USB task. */
    if (pdPASS != xTaskCreate( vUserInterfaceTask, ( int8_t * ) "User Interface", configMINIMAL_STACK_SIZE, ( void * ) NULL,
            tskIDLE_PRIORITY, NULL))
    {
        ui_printf("Couldn't create User Interface Task\n");
    }
}

/**
 * User interface Task
 *
 * @param  none
 * @return none
 *
 * @brief  decode command entered to UART user interface
 * 		   task is woken by UART ISR
 *
 */
void vUserInterfaceTask(void *pvParameters)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    p_ui_message = ui_message;
    ui_printf(USER_IF_STRING);
    uint8_t rx_data;

    /* Task main Loop */
    while (1)
    {
        xQueueReceive(xUart_Queue, &rx_data, portMAX_DELAY);

        /* send echo */
        uart_send_byte(rx_data);

        /* handle char in user interface */
        user_interface_receive_byte(rx_data);
    }
}

/**
 * receive byte in user interface
 *
 * @param  uint8_t rx_data received data byte
 * @return none
 *
 * @brief  handle different commands and control bytes
 *
 */
void user_interface_receive_byte(uint8_t rx_data)
{
    /* recognize special characters */
    switch (rx_data)
    {
    case '\r':
    case '\n':
        *p_ui_message = '\0';
        /* is just the enter key pressed? */
        if (p_ui_message != ui_message)
        {
            /* parse command */
            user_interface_parse_cmd(ui_message);
        }
        ui_printf("\n");
        /* print UI */
        ui_printf(USER_IF_STRING);
        /* reset message pointer to start*/
        p_ui_message = ui_message;
        break;

    case '\b':          /* BACKSPACE */
    case 127:           /* standard backspace in putty */
        /* char in buffer */
        if (p_ui_message > ui_message)
        {
            /* delete buffer content */
            p_ui_message--;
        }
        break;

    default:
        /* avoid buffer overflow */
        if (*p_ui_message < CFG_MAX_UI_MSG_SIZE)
        {
            /* add char to the input buffer */
            *p_ui_message++ = rx_data;
        }
        break;
    }

}


/**
 * Command parsing
 *
 * @param  uint8_t *data command start
 * @return none
 *
 * @brief  look if command and arguments are correct
 *         call corresponding command function
 *
 */
void user_interface_parse_cmd(uint8_t *data)
{
    uint8_t i = 0, arg_count = 0;
    uint8_t command_recognized = 0x00;
    int8_t *arg[10];
    int8_t * arg_parsed;
    int8_t* cmd;

    /* parse arguments */
    arg_parsed = strtok(data, " ");

    /* while arguments exist */
    while (arg_parsed != NULL)
    {
        /* save argument in list */
        arg[arg_count++] = arg_parsed;

        /* go to next argument*/
        arg_parsed = strtok(NULL, " ");
    }

    /* command is also parsed */
    arg_count--;

    /* step trough all commands in list */
    while (ui_cmd_tbl[i].func != NULL)
    {
        /* we found a matching cmd? */
        if (strcmp(ui_cmd_tbl[i].command, data) == 0)
        {
            /* check argument count */
            if ((ui_cmd_tbl[i].minArgs >= arg_count) && (ui_cmd_tbl[i].maxArgs <= arg_count))
            {
                /* run cmd */
                ui_cmd_tbl[i].func(0, &arg[1]);
            }
            else
            {
                /* argument count not accepted */
                ui_printf("\nwrong number of args\n %x - %x args accepted \n", ui_cmd_tbl[i].minArgs, ui_cmd_tbl[i].maxArgs);
            }

            /* command was found in cmd list */
            command_recognized = 1;
            break;
        }
        i++;
    }

    /* command not recogized */
    if (command_recognized == 0x00)
    {
        ui_printf("\ncommand %s not in list, type 'help' to see all cmds\n", data);
    }

}

